#include <math.h>
#include "Windows.h"
#include "cJSON.h"
#include <Python.h>

#define EXPORT __declspec(dllexport)
#define PI 3.14159265358979323846

typedef struct {
    char *khorizontal;
    char *kvertical;
    char *kcustom;
    char *ktoggle;
} ShortcutKeys;

typedef struct {
    char hotkey[20];
    char keyvalue[20];
} KeyValuePair;

typedef struct {
    KeyValuePair entries[4];
} GlobalKeys;

// 定义一个全局变量，用于保存快捷键
static GlobalKeys global_keys = {
    .entries[0] = { "horizontal", "ctrl+h" },
    .entries[1] = { "vertical", "ctrl+t" },
    .entries[2] = { "custom", "ctrl+p" },
    .entries[3] = { "toggle", "ctrl+o" }
};

void init_shortcut_keys(ShortcutKeys *keys) {
    keys->khorizontal = strdup(global_keys.entries[0].keyvalue);
    keys->kvertical = strdup(global_keys.entries[1].keyvalue);
    keys->kcustom = strdup(global_keys.entries[2].keyvalue);
    keys->ktoggle = strdup(global_keys.entries[3].keyvalue);
}

void init_gkeys(GlobalKeys *gkeys){
    for (int i = 0; i < 4; i++) {
        strcpy(gkeys->entries[i].hotkey, global_keys.entries[i].hotkey);
        strcpy(gkeys->entries[i].keyvalue, global_keys.entries[i].keyvalue);
    }
}

void save_shortcut_keys(GlobalKeys *gkeys) {
    cJSON *root = cJSON_CreateObject();
    if (!root) {
        PyErr_SetString(PyExc_RuntimeError, "Failed to create JSON object");
        return;
    }
    
    cJSON_AddStringToObject(root, "horizontal", gkeys->entries[0].keyvalue);
    cJSON_AddStringToObject(root, "vertical", gkeys->entries[1].keyvalue);
    cJSON_AddStringToObject(root, "custom", gkeys->entries[2].keyvalue);
    cJSON_AddStringToObject(root, "toggle", gkeys->entries[3].keyvalue);

    FILE *file = fopen("shortcut.json", "w");
    if (file) {
        char *json_str = cJSON_Print(root);
        if (json_str) {
            fputs(json_str, file);
            free(json_str);
        } else {
            PyErr_SetString(PyExc_RuntimeError, "Failed to print JSON object");
        }
        fclose(file);
    } else {
        PyErr_SetString(PyExc_RuntimeError, "Failed to open file for writing");
    }
    cJSON_Delete(root);
}

int load_shortcut_keys(ShortcutKeys *keys) {
    FILE *file = fopen("shortcut.json", "r");
    if (!file) {
        save_shortcut_keys(&global_keys);
        FILE *file_new = fopen("shortcut.json", "r");
        if (!file_new) {
            PyErr_SetString(PyExc_RuntimeError, "Failed to open file for reading");
            return -1;
        }
        fseek(file_new, 0, SEEK_END);
        long fsize = ftell(file_new);
        fseek(file_new, 0, SEEK_SET);
        char *json_str = malloc(fsize + 1);
        if (!json_str) {
            fclose(file_new);
            return -1;
        }
        
        fread(json_str, 1, fsize, file_new);
        json_str[fsize] = 0;
        cJSON *root = cJSON_Parse(json_str);
        if (!root) {
            free(json_str);
            fclose(file_new);
            return -1;
        }
        
        cJSON *item;
        if ((item = cJSON_GetObjectItemCaseSensitive(root, "horizontal"))) {
            if (keys->khorizontal) free(keys->khorizontal);
            keys->khorizontal = strdup(item->valuestring);
        }
        if ((item = cJSON_GetObjectItemCaseSensitive(root, "vertical"))) {
            if (keys->kvertical) free(keys->kvertical);
            keys->kvertical = strdup(item->valuestring);
        }
        if ((item = cJSON_GetObjectItemCaseSensitive(root, "custom"))) {
            if (keys->kcustom) free(keys->kcustom);
            keys->kcustom = strdup(item->valuestring);
        }
        if ((item = cJSON_GetObjectItemCaseSensitive(root, "toggle"))) {
            if (keys->ktoggle) free(keys->ktoggle);
            keys->ktoggle = strdup(item->valuestring);
        }
        
        strcpy(global_keys.entries[0].keyvalue, keys->khorizontal);
        strcpy(global_keys.entries[1].keyvalue, keys->kvertical);
        strcpy(global_keys.entries[2].keyvalue, keys->kcustom);
        strcpy(global_keys.entries[3].keyvalue, keys->ktoggle);
        
        cJSON_Delete(root);
        free(json_str);
        fclose(file);
        return 0;       
    }
    else {
    
        fseek(file, 0, SEEK_END);
        long fsize = ftell(file);
        fseek(file, 0, SEEK_SET);
        char *json_str = malloc(fsize + 1);
        if (!json_str) {
            fclose(file);
            return -1;
        }
        
        fread(json_str, 1, fsize, file);
        json_str[fsize] = 0;
        cJSON *root = cJSON_Parse(json_str);
        if (!root) {
            free(json_str);
            fclose(file);
            return -1;
        }
        
        cJSON *item;
        if ((item = cJSON_GetObjectItemCaseSensitive(root, "horizontal"))) {
            if (keys->khorizontal) free(keys->khorizontal);
            keys->khorizontal = strdup(item->valuestring);
        }
        if ((item = cJSON_GetObjectItemCaseSensitive(root, "vertical"))) {
            if (keys->kvertical) free(keys->kvertical);
            keys->kvertical = strdup(item->valuestring);
        }
        if ((item = cJSON_GetObjectItemCaseSensitive(root, "custom"))) {
            if (keys->kcustom) free(keys->kcustom);
            keys->kcustom = strdup(item->valuestring);
        }
        if ((item = cJSON_GetObjectItemCaseSensitive(root, "toggle"))) {
            if (keys->ktoggle) free(keys->ktoggle);
            keys->ktoggle = strdup(item->valuestring);
        }
        
        strcpy(global_keys.entries[0].keyvalue, keys->khorizontal);
        strcpy(global_keys.entries[1].keyvalue, keys->kvertical);
        strcpy(global_keys.entries[2].keyvalue, keys->kcustom);
        strcpy(global_keys.entries[3].keyvalue, keys->ktoggle);
        
        cJSON_Delete(root);
        free(json_str);
        fclose(file);
        return 0;
    }
}

void modify_shortcut_key(const char *key, const char *new_shortcut) {
    if (strcmp(key, "horizontal") == 0) {
        strcpy(global_keys.entries[0].keyvalue, new_shortcut);
    } else if (strcmp(key, "vertical") == 0) {
        strcpy(global_keys.entries[1].keyvalue, new_shortcut);
    } else if (strcmp(key, "custom") == 0) {
        strcpy(global_keys.entries[2].keyvalue, new_shortcut);
    } else if (strcmp(key, "toggle") == 0) {
        strcpy(global_keys.entries[3].keyvalue, new_shortcut);
    }
}

EXPORT void init_shortcut_keys_c() {
    ShortcutKeys *keys = (ShortcutKeys*)malloc(sizeof(ShortcutKeys));
    init_shortcut_keys(keys);
    if (load_shortcut_keys(keys) != 0) {
        PyErr_SetString(PyExc_RuntimeError, "Failed to load shortcut keys");
    }
    free(keys);
    keys = NULL;
    GlobalKeys *gkeys = (GlobalKeys*)malloc(sizeof(GlobalKeys));
    if (!gkeys) {
        PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for global keys");
        return;
    }
    init_gkeys(gkeys);
    save_shortcut_keys(gkeys);
    free(gkeys);
    gkeys = NULL;
}

EXPORT void modify_shortcut_key_c(const char *key, const char *new_shortcut) {
    ShortcutKeys *keys = (ShortcutKeys*)malloc(sizeof(ShortcutKeys));
    init_shortcut_keys(keys);
    if (load_shortcut_keys(keys) == 0) {
        free(keys);
        keys = NULL;
        modify_shortcut_key(key, new_shortcut);
        GlobalKeys *gkeys = (GlobalKeys*)malloc(sizeof(GlobalKeys));
        if (!gkeys) {
            PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for global keys");
            return;
        }
        init_gkeys(gkeys);
        save_shortcut_keys(gkeys);
        free(gkeys);
        gkeys = NULL;
    } else {
        PyErr_SetString(PyExc_RuntimeError, "Failed to load shortcut keys for modification");
    }
}

EXPORT void control_mouse_position_c(int last_mouse_pos_x, int last_mouse_pos_y, int current_mouse_pos_x, int current_mouse_pos_y, double direction, double amplitude_limit) {
    double angle_radians = direction * (PI / 180.0);
    double cos_angle = cos(angle_radians);
    double sin_angle = sin(angle_radians);
    double dx = current_mouse_pos_x - last_mouse_pos_x;
    double dy = current_mouse_pos_y - last_mouse_pos_y;
    double distance = dx * cos_angle + dy * sin_angle;
    double new_x = last_mouse_pos_x + distance * cos_angle;
    double new_y = last_mouse_pos_y + distance * sin_angle;
    double error_distance = sqrt(pow(new_x - current_mouse_pos_x, 2) + pow(new_y - current_mouse_pos_y, 2));

    if (error_distance > amplitude_limit) {
        SetCursorPos((int)new_x, (int)new_y);
    }

}

EXPORT GlobalKeys* load_shortcut_keys_c() {
    ShortcutKeys *keys = (ShortcutKeys*)malloc(sizeof(ShortcutKeys));
    init_shortcut_keys(keys);
    if (load_shortcut_keys(keys) != 0) {
        PyErr_SetString(PyExc_RuntimeError, "Failed to load shortcut keys");
        return NULL;
    }
    free(keys);
    keys = NULL;
    return &global_keys;
}
